#pragma once
//#include "stdafx.h"
#include "GridSpace.h"
namespace org
{
	namespace spark
	{
		namespace space
		{

			GridSpace::GridSpace(double xMin, double xMax, double yMin, double yMax, bool wrapX, bool wrapY) : BoundedSpace(xMin, xMax, yMin, yMax, wrapX, wrapY)
			{

				// FIXME: convert non-integer dimension into integer ones
				if (floor(xMin) != xMin || floor(yMin) != yMin || floor(xMax) != xMax || floor(yMax) != yMax)
						//throw Error("NetLogoSpace: non-integer dimensions");

				// xMin, etc should be set before
				hashGrid = new HashGrid2d(this, static_cast<int>(getXSize()), static_cast<int>(getYSize()));
			}

			void GridSpace::addNode0(SpaceNode *node)
			{
				SpaceNode *node1 = hashGrid->getNode(node->position->x, node->position->y);
				node->next = node1->next;
				node1->next->prev = node;
				node->prev = node1;
				node1->next = node;
			}

			void GridSpace::removeNode0(SpaceNode *node)
			{
				node->prev->next = node->next;
				node->next->prev = node->prev;
			}

			void GridSpace::addNodeAndMove0(SpaceNode *node)
			{
				double x = node->newPosition->x;
				double y = node->newPosition->y;

				// TODO: make a test how much did the previous (incorrect)
				// solution work faster than the present (correct) one
				x = restrictX(x);
				y = restrictY(y);
						/*		if (x < xMin) {
									if (wrapX)
										x += getXSize();
									else
										x = xMin;
								}
								else if (x >= xMax) {
									if (wrapX)
										x -= getXSize();
									else
										x = xMax;
								}
								
								if (y < yMin) {
									if (wrapY)
										y += getYSize();
									else
										y = yMin;
								}
								else if (y >= yMax) {
									if (wrapY)
										y -= getYSize();
									else
										y = yMax;
								}*/

				node->position->set(x, y);

				SpaceNode *node1 = hashGrid->getNode(x, y);
				node->next = node1->next;
				node1->next->prev = node;
				node->prev = node1;
				node1->next = node;
			}

			void GridSpace::changeNodePosition0(SpaceNode *node)
			{
				double x = node->newPosition->x;
				double y = node->newPosition->y;

				x = restrictX(x);
				y = restrictY(y);

						/*		if (x < xMin) {
									if (wrapX)
										x += getXSize();
									else
										x = xMin;
								}
								else if (x >= xMax) {
									if (wrapX)
										x -= getXSize();
									else
										x = xMax;
								}
								
								if (y < yMin) {
									if (wrapY)
										y += getYSize();
									else
										y = yMin;
								}
								else if (y >= yMax) {
									if (wrapY)
										y -= getYSize();
									else
										y = yMax;
								}*/

				node->position->set(x, y);

				node->prev->next = node->next;
				node->next->prev = node->prev;

				SpaceNode *node1 = hashGrid->getNode(x, y);
				node->next = node1->next;
				node1->next->prev = node;
				node->prev = node1;
				node1->next = node;
			}

			std::vector<SpaceAgent*> GridSpace::getAgents(SpaceNode *node)
			{
				// TODO: if the mode is not parallel then can use a global set
				std::vector<SpaceAgent*> result = std::vector<SpaceAgent*>(10);
						//		result.clear();

				int x0 = hashGrid->findX(node->position->x);
				int y0 = hashGrid->findY(node->position->y);

				SpaceNode *first = hashGrid->getNode(x0, y0);
				SpaceNode *next = first->next;

				while (next != first)
				{
					result.push_back(next->agent);
					next = next->next;
				}

				return result;
			}

// There is no native C++ template equivalent to generic constraints:
template<typename T> where T : SpaceAgent
			std::vector<T> GridSpace::getAgents(SpaceNode *node, Class *type)
			{
				// TODO: if the mode is not parallel then can use a global set
				std::vector<SpaceAgent*> result = std::vector<SpaceAgent*>(10);
						//		result.clear();

				int x0 = hashGrid->findX(node->position->x);
				int y0 = hashGrid->findY(node->position->y);

				SpaceNode *first = hashGrid->getNode(x0, y0);
				SpaceNode *next = first->next;

				while (next != first)
				{
					if (next->agent->getClass() == type)
					{
						result.push_back(next->agent);
					}
					next = next->next;
				}

				return static_cast<std::vector<T>>(result);
			}

// There is no native C++ template equivalent to generic constraints:
template<typename T> where T : SpaceAgent
			std::vector<T> GridSpace::getAgentsOfKind(SpaceNode *node, Class *type)
			{
				// TODO: if the mode is not parallel then can use a global set
				std::vector<SpaceAgent*> result = std::vector<SpaceAgent*>(10);
						//		result.clear();

				int x0 = hashGrid->findX(node->position->x);
				int y0 = hashGrid->findY(node->position->y);

				SpaceNode *first = hashGrid->getNode(x0, y0);
				SpaceNode *next = first->next;

				while (next != first)
				{
					if (type->isInstance(next->agent))
					{
						result.push_back(next->agent);
					}

					next = next->next;
				}

				return static_cast<std::vector<T>>(result);
			}

			void GridSpace::readObject(ObjectInputStream *ois) //throw(IOException, ClassNotFoundException)
			{

				ois->defaultReadObject();

				// Load hash grid
				hashGrid = new HashGrid2d(this, static_cast<int>(getXSize()), static_cast<int>(getYSize()));
			}

			void GridSpace::writeObject(ObjectOutputStream *oos) //throw(IOException)
			{
				oos->defaultWriteObject();
			}
		}
	}
}
